/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ania2;

import ania2.enums.Fields;
import ania2.enums.FieldStatesEnum;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

/**
 *
 * @author pawel
 */
public class SetupPositionBoardListener implements MouseListener {

    private BoardPosition position;
    private int border;
    private int fieldWidth;
    private int state;
    public static final String PROP_STATE = "state";
    private FieldStatesEnum[] states = FieldStatesEnum.values();
    private long whites;
    private long blacks;
    private long queens;

    public SetupPositionBoardListener(BoardPosition position, int border, int size) {
        this.position = position;
        this.border = border;
        updateBoardSize(size);
        getComponents();
    }

    /**
     * Get the value of state
     *
     * @return the value of state
     */
    public int getState() {
        return state;
    }

    /**
     * Set the value of state
     *
     * @param state new value of state
     */
    public void setState(int state) {
        int oldState = this.state;
        this.state = state;
        propertyChangeSupport.firePropertyChange(PROP_STATE, oldState, state);
    }
    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    /**
     * Add PropertyChangeListener.
     *
     * @param listener
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    /**
     * Remove PropertyChangeListener.
     *
     * @param listener
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    public void updateBoardSize(int size) {
        this.fieldWidth = (size - 2 * border) / 8;
    }

    public void mousePressed(MouseEvent e) {
        getComponents();
        Point p = e.getPoint();
        int column = (int) Math.ceil((p.x - border) / fieldWidth);
        int row = (int) Math.ceil((p.y - border) / fieldWidth);
        String name = String.valueOf(Character.toChars('A' + column)) + (8 - row);
        try {
            int fieldIndex = Fields.valueOf(name).ordinal();
            if (getPieceState(fieldIndex).ordinal() == state) {
                int old = state;
                changeState(state);
                propertyChangeSupport.firePropertyChange(PROP_STATE, old, state);
            }
            //change black piece to queen if necessary
            if((8-row)==1 && state==FieldStatesEnum.BLACK_PIECE.ordinal()) {
                state = FieldStatesEnum.BLACK_QUEEN.ordinal();
                propertyChangeSupport.firePropertyChange(PROP_STATE,
                        FieldStatesEnum.BLACK_PIECE, FieldStatesEnum.BLACK_QUEEN);
            }
            //change white piece to queen if necessary
            else if((8-row)==8 && state==FieldStatesEnum.WHITE_PIECE.ordinal()) {
                state = FieldStatesEnum.WHITE_QUEEN.ordinal();
                propertyChangeSupport.firePropertyChange(PROP_STATE, 
                        FieldStatesEnum.WHITE_PIECE, FieldStatesEnum.BLACK_QUEEN);
            }
            int oldState = getPieceState(fieldIndex).ordinal();
            updatePosition(fieldIndex, state);
            propertyChangeSupport.firePropertyChange("position", oldState, state);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
    }

    private void changeState(int state) {
        FieldStatesEnum s = states[state];
        switch (s) {
            case EMPTY:
                this.state = FieldStatesEnum.WHITE_PIECE.ordinal();
                break;
            case WHITE_PIECE:
                this.state = FieldStatesEnum.WHITE_QUEEN.ordinal();
                break;
            case WHITE_QUEEN:
                this.state = FieldStatesEnum.BLACK_PIECE.ordinal();
                break;
            case BLACK_PIECE:
                this.state = FieldStatesEnum.BLACK_QUEEN.ordinal();
                break;
            case BLACK_QUEEN:
                this.state = FieldStatesEnum.EMPTY.ordinal();
                break;
            default:
                break;
        }
    }

    private FieldStatesEnum getPieceState(int fieldIndex) {
        long field = (1L << (63-fieldIndex));
        if((whites & field) != 0) {
            if((queens & field) !=0)
                return FieldStatesEnum.WHITE_QUEEN;
            return FieldStatesEnum.WHITE_PIECE;
        }
        else if((blacks & field) != 0) {
            if((queens & field) !=0)
                return FieldStatesEnum.BLACK_QUEEN;
            return FieldStatesEnum.BLACK_PIECE;
        }
        return FieldStatesEnum.EMPTY;
    }

    private void updatePosition(int fieldIndex, int state) {
        long field = (1L << (63-fieldIndex));
        FieldStatesEnum s = states[state];
        FieldStatesEnum old = getPieceState(fieldIndex);
        clearOldPiece(field, old);
        switch(s) {
            case EMPTY: break;
            case WHITE_PIECE:
                whites |= field;
                break;
            case WHITE_QUEEN:
                whites |= field;
                queens |= field;
                break;
            case BLACK_PIECE:
                blacks |= field;
                break;
            case BLACK_QUEEN:
                blacks |= field;
                queens |= field;
                break;
            default:
                break;
        }
        position.setBlackPieces(blacks);
        position.setWhitePieces(whites);
        position.setQueens(queens);
    }

    private void clearOldPiece(long field, FieldStatesEnum old) {
        switch(old) {
            case WHITE_PIECE:
                whites ^= field;
                break;
            case WHITE_QUEEN:
                whites ^= field;
                queens ^= field;
                break;
            case BLACK_PIECE:
                blacks ^= field;
                break;
            case BLACK_QUEEN:
                blacks ^= field;
                queens ^= field;
                break;
            default:
                break;
        }
    }

    private void getComponents() {
        whites = position.getWhitePieces();
        blacks = position.getBlackPieces();
        queens = position.getQueens();
    }
    
    public void mouseEntered(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseExited(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseClicked(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseReleased(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void setBorder(int border) {
        this.border = border;
    }

    public void setPosition(BoardPosition position) {
        this.position = position;
    }
}
